import { deprecate } from "core-decorators"; // 第三方decorators库

{
  class People {
    constructor(name, age) {
      this.name = name;
      this.age = age;
    }
    @deprecate("core-decorators 废弃了", { url: "www.baidu.com" })
    eat() {
      console.log(`${this.name} eat`);
    }
    speak() {
      console.log(`${this.name} speak, age ${this.age}`);
    }
  }

  class Student extends People {
    constructor(name, age, number) {
      super(name, age);
      this.number = number;
    }
    study() {
      console.log(`${this.name} study`);
    }
  }

  let xiaoming = new Student("xiaoming", 10, "A1");
  console.log(xiaoming.number);
  xiaoming.study();
  xiaoming.eat();

  let xiaohong = new Student("xiaohong", 10, "A1");
  console.log(xiaohong.number);
  xiaohong.study();
  xiaohong.eat();
}

// 快车专车问题
{
  class Car {
    constructor(number, name) {
      this.number = number;
      this.name = name;
    }
  }

  class Trip {
    constructor(car) {
      this.car = car;
    }
    begin() {
      console.log(`${this.car.name} ${this.car.number}`);
    }
    end() {
      console.log(`${this.car.price * 5}`);
    }
  }

  class Zhuanche extends Car {
    constructor(number, name) {
      super(number, name);
      this.price = 2;
    }
  }

  class Kuaiche extends Car {
    constructor(number, name) {
      super(number, name);
      this.price = 1;
    }
  }

  let car = new Zhuanche("342453", "奥迪");
  let trip = new Trip(car);
  trip.begin();
  trip.end();
}

// 停车场问题
{
  class Camera {
    // 存储信息
    shot(car) {
      return {
        number: car.number,
        inTime: Date.now()
      };
    }
  }
  class Screen {
    show(car, inTime) {
      console.log(`${car.number}停车${Date.now() - inTime}ms`);
    }
  }
  class Park {
    constructor(floors) {
      this.floors = floors || [];
      this.carList = {};
      this.camera = new Camera();
      this.screen = new Screen();
    }
    emptyNum() {
      return this.floors
        .map(item => {
          return `第${item.index}层有${item.emptyPlaceNum()}个车位`;
        })
        .join("\n");
    }
    in(car) {
      // 假设停在第一层的随机的一个停车位
      const info = this.camera.shot(car);
      const i = parseInt((Math.random() * 200) % 100);
      const place = this.floors[0].places[i];
      place.in();
      info.place = place;
      this.carList[car.number] = info;
    }
    out(car) {
      const info = this.carList[car.number];
      const place = info.place;
      place.out();
      this.screen.show(car, info.inTime);
      delete this.carList[car.number];
    }
  }
  class Floor {
    constructor(places, index) {
      this.places = places;
      this.index = index;
    }
    emptyPlaceNum() {
      let emptyNum = 0;
      this.places.forEach(item => {
        if (item.empty) {
          emptyNum++;
        }
      });
      return emptyNum;
    }
  }
  class Place {
    constructor() {
      this.empty = true;
    }
    in() {
      this.empty = false;
    }
    out() {
      this.empty = true;
    }
  }
  class Car {
    constructor(number) {
      this.number = number;
    }
  }
  let floors = [];
  for (let i = 0; i < 3; i++) {
    let places = [];
    for (let j = 0; j < 100; j++) {
      places.push(new Place());
    }
    let floor = new Floor(places, i + 1);
    floors.push(floor);
  }
  let park = new Park(floors);
  let car1 = new Car(10001);
  let car2 = new Car(10002);
  let car3 = new Car(10003);
  console.log(park.emptyNum());
  console.log("第1辆进入");
  park.in(car1);
  console.log(park.emptyNum());
  console.log("第2辆进入");
  park.in(car2);
  // setTimeout(() => {
  console.log("第1辆离开");
  park.out(car1);
  console.log("第2辆离开");
  park.out(car2);
  console.log(park.emptyNum());
  console.log("第3辆进入");
  park.in(car3);
  console.log("第3辆离开");
  park.out(car3);
  // }, 1000);
}

// 工厂模式
{
  class Product {
    constructor(name) {
      this.name = name;
    }
    init() {
      console.log("init");
    }
    fun1() {
      console.log("fun1");
    }
    fun2() {
      console.log("fun2");
    }
  }

  class Creator {
    creat(name) {
      return new Product(name);
    }
  }

  let creator = new Creator();
  let p = creator.creat("666");
  p.init();
}

// 单例模式
{
  class SingleObject {
    login() {
      console.log("login...");
    }
  }
  SingleObject.getInstance = (function() {
    let instance;
    return function() {
      if (!instance) {
        instance = new SingleObject();
      }
      return instance;
    };
  })();

  let o1 = SingleObject.getInstance();
  let o2 = SingleObject.getInstance();
  console.log(o1 === o2);
}

// 适配器模式
{
  class Adaptee {
    specificRequest() {
      return "德国标准插头";
    }
  }

  class Target {
    constructor() {
      this.adaptee = new Adaptee();
    }
    request() {
      let info = this.adaptee.specificRequest();
      return `${info}-转换-中国标准插头`;
    }
  }

  let target = new Target();
  let request = target.request();
  console.log(request);
}

// 装饰器模式
{
  class Circle {
    draw() {
      console.log("画一个圆形");
    }
  }

  class Decorator {
    constructor(circle) {
      this.circle = circle;
    }
    draw() {
      this.circle.draw();
      this.setRedBorder(this.circle);
    }
    setRedBorder(circle) {
      console.log("画红色边框");
    }
  }

  let circle = new Circle();
  circle.draw();
  console.log("----");
  let dec = new Decorator(circle);
  dec.draw();
}

// es7 装饰器
{
  @testDec
  class Demo {}
  function testDec(target) {
    target.isDec = true;
  }
  console.log(Demo.isDec);
}

{
  @testDec(false)
  class Demo {}
  function testDec(isDec) {
    return function(target) {
      target.isDec = isDec;
    };
  }
  console.log(Demo.isDec);
}

{
  function readOnly(target, name, descriptor) {
    descriptor.writable = false;
    return descriptor;
  }
  class Person {
    constructor() {
      this.firstName = "a";
      this.lastName = "b";
    }

    @readOnly
    getName() {
      return this.firstName + this.lastName;
    }
  }

  let person = new Person();
  console.log(person.getName());
  // person.getName = 111; // 报错
}

{
  function log(target, name, descriptor) {
    let oldValue = descriptor.value;
    descriptor.value = function() {
      // 这里不能使用剪头函数，使用剪头函数this就指向了log
      console.log(`${name}-`, arguments);
      return oldValue.apply(this, arguments); // 运行时的this
    };
    return descriptor;
  }

  class Math {
    @log
    add(a, b) {
      return a + b;
    }
  }

  let math = new Math();
  math.add(1, 2);
}

{
  function mixin(...list) {
    return function(target) {
      Object.assign(target.prototype, ...list);
    };
  }

  let obj = {
    say() {
      console.log("say");
    }
  };

  @mixin(obj)
  class Demo {
    //
  }

  let demo = new Demo();
  demo.say();
}

// es6 proxy
{
  let star = {
    name: "张三",
    age: 20,
    phone: "13111111111"
  };

  let proxy = new Proxy(star, {
    get(target, key) {
      console.log(target[key]);
      return target[key];
    },
    set(target, key, value) {
      target[key] = value;
      console.log(target[key]);
      return true; // 必须返回true
    }
  });

  proxy.name;
  proxy.name = "李四";
  proxy.name;
}

// 外观模式
{
  function bindEvent(elem, type, selector, fn) {
    if (fn == null) {
      fn = selector;
      selector = null;
    }
  }
  // bindEvent(elem, "click", "#div", fn);
  // bindEvent(elem, "click", fn);
}

// 观察者模式
{
  class Subject {
    constructor() {
      this.state = 0;
      this.observers = [];
    }
    getState() {
      return this.state;
    }
    setState(state) {
      this.state = state;
      this.notifyAllObservers();
    }
    notifyAllObservers() {
      this.observers.forEach(observer => {
        observer.update();
      });
    }
    attach(observer) {
      this.observers.push(observer);
    }
  }

  class Observe {
    constructor(name, subject) {
      this.name = name;
      this.subject = subject;
      this.subject.attach(this);
    }
    update() {
      console.log(`${this.name} update ${this.subject.getState()}`);
    }
  }
  let s = new Subject();
  let o1 = new Observe("o1", s);
  let o2 = new Observe("o2", s);
  let o3 = new Observe("o3", s);

  s.setState(666);
}
